import numpy
import linecache
import os
import random

'''
LinRel algorithm
Uses distance matrix from '/ProximityMatrix/features_lewis1000_Euclidean.dist'
The algorithm is called in ExperimentLinRel
'''

class LinRel(object):
    
    MU = 0.5
    C = 0.4
    E = 0.001


    def __init__(self, filename, N):
        self.number_of_images = N
        self.previous_images = []
        self.images_presented = numpy.array(())
        self.relevance_scores = numpy.array(())
        self.input = os.path.dirname(__file__) + '-files/'+ filename + '_Euclidean.dist.npy'
        self.distances = numpy.load(self.input)
        '''self.input = os.path.dirname(__file__) + '-files/'+ filename
        self.distances = numpy.loadtxt(self.input)'''
    
    def ChooseFirstImageSet(self, setsize):
        chosen_images = []
        while len(chosen_images) < setsize:
            image = random.randint(0, self.number_of_images-1)
            if image not in chosen_images:
                chosen_images.append(image)
        # save images as been presented
        self.previous_images = chosen_images        
        return chosen_images
        
    def GetImageVector(self, number):
        '''# Get vector from line #number from file input
        # number starts from 1
        
        line = linecache.getline(self.input, number+1)
        image = numpy.array((map(float, line.split())))
   #     return numpy.exp(image)
        return numpy.array(image)'''
        return self.distances[number]
        
        # for sample-docs
        #return map(float, line.split()[1:])
        
    # Learning function
    # User_feedback is a dictionary with keywords and their weighs about which we got the feedback
    def LinRel(self, images, relevance_scores, setsize): 
        
        selectioncriteria = []
               
        # Matrix representing topic models for documents that have already been presented
        for image in relevance_scores.keys():

            imagevector = self.GetImageVector(image)
            # For all keywords from user feedback, add them to arrays of keywords_presented and the user feedback about them to relevance_scores 
            if (numpy.shape(self.images_presented)[0]==0):
                self.images_presented = imagevector
                self.relevance_scores = numpy.array(relevance_scores[image])
            else: 
                self.images_presented = numpy.vstack((self.images_presented, imagevector))
                self.relevance_scores = numpy.hstack((self.relevance_scores, relevance_scores[image]))  
        
        # LinRel computations        
        # Diagonal matrix with mu on the diagonal
        Mu = LinRel.MU*numpy.eye(numpy.shape(self.images_presented)[1])
        # temporary variable which is the same for all images
        temp = numpy.linalg.inv(numpy.dot(self.images_presented.T, self.images_presented)+Mu)
        # For all the keywords
        for image in range(self.number_of_images):
            # Keyword representation in terms of article tf-idf for every keyword
            xI = self.GetImageVector(image)
            aI = numpy.dot(numpy.dot(xI,temp),self.images_presented.T)
            # Calculate the criteria by which to decide with document to choose next
            # Upper confidence bound on score of the keyword
            # To prevent 0 feedback on the first iteration we add small number E to relevance scores values
            # But still the relevance scores values are not changed and words are put into the stop list when they get 0  
            #selectioncriteria.append(float(numpy.dot(aI, self.relevance_scores.T+LinRel.E)+LinRel.C/2*numpy.dot(aI, aI.T)))
            selectioncriteria.append(float(numpy.dot(aI, self.relevance_scores.T)+LinRel.C/2*numpy.dot(aI, aI.T)))
            
        chosen_images = []
        indeces = numpy.argsort(numpy.array(selectioncriteria))
        i = 0
        while len(chosen_images) < setsize:
            # starting from the last image
            image = indeces[len(indeces)-i-1]
            if image not in self.previous_images:
                chosen_images.append(image)
            i += 1
        self.previous_images = chosen_images
        
     
        return chosen_images    